/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package percussiongenerator.gui.view;

import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.FocusListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.intervals.Interval;
import org.jfonia.connect5.intervals.ListObserver;
import org.jfonia.model.PerformanceSequence;
import org.jfonia.model.TempoNode;
import org.jfonia.model.elements.Tone;
import percussiongenerator.commands.CommandHistory;
import percussiongenerator.commands.RemoveMultipleIntervals;
import percussiongenerator.commands.RemoveTrack;
import percussiongenerator.languages.ILanguageDependent;
import percussiongenerator.model.Pair;
import percussiongenerator.model.Track;

/**
 *
 * @author Jannes Plyson
 */
public abstract class View extends JPanel implements ILanguageDependent,MouseListener,KeyListener,FocusListener,Observer,ListObserver,MouseWheelListener{
    public static int SIMPLE_VIEW = 0;
    protected static MutableValueNode<Integer> zoom = new BasicValueNode<Integer>(10000);
    protected Track track;          
    protected Color selectedBackgroundColor;
    protected Color selectedForegroundColor;
    protected Color unselectedBackgroundColor;
    protected Color mutedColor;
    protected Color backgroundColor;
    protected MutableValueNode<View> selectedView;
    protected MutableValueNode<Integer> widthNode;
    protected MutableValueNode<Integer> heightNode;
    protected MutableValueNode<ArrayList<Integer>> selectedInterval;
    protected ViewOptionsPanel viewOptions;
    protected boolean mousePressed;
    protected Pair<Point,Point> mousePressedStart,mousePressedEnd; //relative position, screen position
    protected static boolean ctrlPressed;
    protected static int mouseButtonPressed;
    protected static View mouseEnteredView;
    protected Pair<String,Object> selection;
    protected TempoNode tempoNode;

    public View(Track track,MutableValueNode<View> selectedView,MutableValueNode<ArrayList<Integer>> selectedInterval){
        this.selectedInterval = selectedInterval;
        this.selectedInterval.addObserver(this);
        this.selectedView = selectedView;
        this.track = track;
        mousePressed = false;
        this.setAlignmentX(0f);        
        zoom.addObserver(this);
        this.addMouseListener(this);
        this.addFocusListener(this);
        this.addKeyListener(this);
        this.addMouseWheelListener(this);
        selectedBackgroundColor = new Color(230,230,230);
        selectedForegroundColor = Color.RED;
        unselectedBackgroundColor = Color.WHITE;
        mutedColor = Color.DARK_GRAY;        
        widthNode = new BasicValueNode<Integer>(0);
        widthNode.addObserver(this);
        heightNode = new BasicValueNode<Integer>(0);
        heightNode.addObserver(this);
        track.getStaff().getToneSequence().getPerformanceSequence().addObserver(this);
        mouseEnteredView = this;
        tempoNode = ((TempoNode)track.getStaff().getTempoMap().getIntervalFromIndex(0));
        tempoNode.getBPMNode().addObserver(this);
    }

    public void removeRelations(){
        track.getStaff().getToneSequence().getPerformanceSequence().removeObserver(this);
        zoom.removeObserver(this);
        tempoNode.getBPMNode().removeObserver(this);
    }

    public ViewOptionsPanel getViewOptions(){
        return viewOptions;
    }

    public void zoomIn(int zoom){
        int newzoom = View.zoom.getValue() + zoom;
        if(newzoom > 100000){
            newzoom = 100000;
        }
        View.zoom.setValue(newzoom);
    }

    public void zoomOut(int zoom){
        int newzoom = View.zoom.getValue() - zoom;
        if(newzoom < 500){
            newzoom = 500;
        }
        View.zoom.setValue(newzoom);
    }

    public abstract void zoomUpdated();

    public abstract void paintView(Graphics g);   

    public final void setSize(){
        Dimension d = new Dimension(widthNode.getValue(),heightNode.getValue());
        this.setMinimumSize(d);
        this.setPreferredSize(d);
        this.setMaximumSize(d);
        revalidate();
    }

    @Override
    public final void paintComponent(Graphics g){
        super.paintComponent(g);
        if(this == selectedView.getValue()){
            backgroundColor = selectedBackgroundColor;
        }else{
            if(track.isMuted()){
                backgroundColor = mutedColor;
            }else{
                backgroundColor = unselectedBackgroundColor;
            }
        }
        g.setColor(backgroundColor);
        g.fillRect(0, 0, getWidth(), getHeight());
        paintView(g);
        //paintTimePointer(g);
    }

    public Track getTrack(){
        return track;
    }

    public final void mouseClicked(MouseEvent e) {}

    public final void mousePressed(MouseEvent e) {
        mousePressedStart = new Pair<Point,Point>(new Point(e.getX(),e.getY()),new Point(e.getXOnScreen(),e.getYOnScreen()));
        mouseButtonPressed = e.getButton();
        mousePressed = true;
        this.requestFocus();        
        mousePressedExtra(e);
    }

    public final void mouseReleased(MouseEvent e) {
        mousePressedEnd = new Pair<Point,Point>(new Point(e.getX(),e.getY()),new Point(e.getXOnScreen(),e.getYOnScreen()));
        mouseButtonPressed = 0;
        mousePressed = false;
        mouseReleasedExtra(e);
    }    

    public final void mouseEntered(MouseEvent e) {
        mouseEnteredView = this;
        mouseEnteredExtra(e);
    }

    public void mousePressedExtra(MouseEvent e){}
    public void mouseReleasedExtra(MouseEvent e){}
    public void mouseEnteredExtra(MouseEvent e){}

    public void mouseExited(MouseEvent e) {}

    public void focusGained(FocusEvent e) {        
        selectedView.setValue(this);
    }

    public void focusLost(FocusEvent e) {        
    }


    public void onNotify(Object source){
        if(source == widthNode || source == heightNode){
            setSize();
        }else if(source == View.zoom){
            zoomUpdated();
        }
        repaint();
    }

    public void keyTyped(KeyEvent e) {        
       
    }

    public void keyPressed(KeyEvent e) {
        if(!ctrlPressed && e.getKeyCode() == KeyEvent.VK_CONTROL){
            ctrlPressed = true;            
        }
         if(e.getKeyCode() == KeyEvent.VK_DELETE){            
            if(selectedInterval.getValue() != null){                
                ArrayList<Interval> list = new ArrayList<Interval>();
                PerformanceSequence perSeq = track.getStaff().getToneSequence().getPerformanceSequence();
                for(int i : selectedInterval.getValue()){
                    list.add(perSeq.getIntervalFromIndex(i));
                }
                CommandHistory.addCommandAndExecute(new RemoveMultipleIntervals(list, perSeq));
                if(perSeq.size() == 0){
                    CommandHistory.addCommandAndExecute(new RemoveTrack(track));
                }
                selectedInterval.setValue(null);
            }else{
                CommandHistory.addCommandAndExecute(new RemoveTrack(track));
            }
        }        
    }

    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_CONTROL){
            ctrlPressed = false;   
        }
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
        int value = e.getWheelRotation();
        zoomOut(value*1000);                
    }
}
